home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / NETSTUFF.ZIP / DELTA.C < prev    next >
C/C++ Source or Header  |  1991-02-27  |  20KB  |  631 lines

  1. /**
  2.      This C language example is printed in Appendix A of Adaptive
  3.      Pattern Recognition and Neural Networks, by Yoh-Han Pao.  The
  4.      algorithm and notation used come from chapter 5 of this book.  The
  5.      program will run under VAX/VMS or PC-DOS/MS-DOS.  The only changes
  6.      I made were to correct an obvious error in the routine called
  7.      "forward()" where the formal parameter lacked a type specification,
  8.      and to decrease some of the defined constants in order to allow
  9.      linking within the constraints of my memory model (see original
  10.      sizes in parentheses inside comments on each).  I hope there are
  11.      no typing errors.  I compiled and linked using Microsoft QuickC 2.0.
  12.  
  13.      For a possible scenario in running this program, see the file named
  14.      "scenario" which uses the files par3.dat and data.dat.  All are
  15.      included on this diskette.
  16.                       Marilyn M. Nelson, February 1991 **/
  17.  
  18. /**
  19.  
  20.      PROGRAM DESCRIPTION:
  21.  
  22.      THIS PROGRAM ALLOWS A USER TO BUILD A GENERALIZED DELTA RULE
  23.      NET FOR SUPERVISED LEARNING.  USER CAN SPECIFY THE NUMBER OF
  24.      INPUT & OUTPUT UNITS, NUMBER OF HIDDEN LAYERS AND NUMBER OF
  25.      UNITS IN EACH HIDDEN LAYER.
  26.  
  27.      AFTER THE NET IS BUILT, LEARNING TAKES PLACE IN THE NET WITH
  28.      A GIVEN SET OF TRAINING SAMPLES.  USER SPECIFIES VALUES OF
  29.      THE LEARNING RATE ETA, THE MOMENTUM RATE ALPHA, MAXIMUM
  30.      TOLERANCE ERRORS AND MAXIMUM NUMBER OF ITERATIONS.
  31.  
  32.      AFTER LEARNING, ALL THE INFORMATION RELEVANT TO THE STRUCTURE
  33.      OF THE NET, INCLUDING WEIGHTS AND THRESHOLDS ARE STORED IN
  34.      FILES.
  35.  
  36.      OUTPUTS CAN BE GENERATED FOR NEW PATTERNS BY READING FROM
  37.      FILE AND BY RECONSTRUCTING THE NET.
  38.  
  39.      TRAINING SET SAMPLES AND ADDITIONAL SAMPLES FOR PROCESSING
  40.      ARE STORED IN FILES.
  41. **/
  42.  
  43. #include <stdio.h>
  44. #include <math.h>
  45. #include <ctype.h>
  46. #ifndef VAX /* for declaration of calloc() on PC or compatible   */
  47. #include <malloc.h>
  48. #endif
  49.  
  50. /* define constants used throughout functions                    */
  51.  
  52. #define   NMXUNIT   40 /* max no. of units in a layer  (50)      */
  53. #define   NMXHLR     3 /* max no. of hidden layers     ( 5)      */
  54. #define   NMXOATTR  40 /* max no. of output features   (50)      */
  55. #define   NMXINP   100 /* max no. of input samples    (200)      */
  56. #define   NMXIATTR  40 /* max no. of input features    (50)      */
  57. #define   SEXIT      3 /* exit successfully                      */
  58. #define   RESTRT     2 /* restart                                */
  59. #define   FEXIT      1 /* exit in failure                        */
  60. #define   CONTNE     0 /* continue calculation                   */
  61.  
  62. /* Data base : declarations of variables */
  63.  
  64. float eta;          /** learning rate             **/
  65. float alpha;        /** momentum rate             **/
  66. float err_curr;     /** normalized system error   **/  
  67. float maxe;         /** max allowed system error  **/
  68. float maxep;        /** max allowed patter error  **/
  69. float *wtptr[NMXHLR+1];
  70. float *outptr[NMXHLR+2];
  71. float *errptr[NMXHLR+2];
  72. float *delw[NMXHLR+1];
  73. float target[NMXINP][NMXOATTR];
  74. float input[NMXINP][NMXIATTR], ep[NMXINP];
  75. float outpt[NMXINP][NMXOATTR];
  76. int   nunit[NMXHLR+2], nhlayer, ninput, ninattr, noutattr;
  77. int   result, cnt, cnt_num;
  78. int   nsnew, nsold;
  79. char  task_name[20];
  80. FILE  *fp1, *fp2, *fp3, *fopen();
  81. int   fplot10;
  82.  
  83.           /* random number generator
  84.              (computer independent)   */
  85.  
  86. long randseed = 568731L;
  87. int random()
  88. {
  89.      randseed = 15625L * randseed + 22221L;
  90.      return((randseed >> 16) & 0x7FFF);
  91. }
  92.  
  93.           /* allocate dynamic storage for the set */
  94. void init()
  95. {
  96.      int len1, len2, i, k;
  97.      float *p1, *p2, *p3, *p4;
  98.  
  99.      len1 = len2 = 0;
  100.      nunit[nhlayer+2] = 0;
  101.  
  102.      for (i=0; i<(nhlayer + 2); i++) {
  103.         len1 += (nunit[i] + 1) * nunit[i+1];
  104.         len2 += nunit[i] + 1;
  105.      }
  106.  
  107.                               /* weights */
  108.      p1=(float *) calloc(len1+1,sizeof(float));
  109.                               /* output  */
  110.      p2=(float *) calloc(len2+1,sizeof(float));
  111.                               /* errors  */
  112.      p3=(float *) calloc(len2+1,sizeof(float));
  113.                               /* delw    */
  114.      p4=(float *) calloc(len1+1,sizeof(float));
  115.  
  116.                /* set up initial pointers */
  117.      wtptr[0]  = p1;
  118.      outptr[0] = p2;
  119.      errptr[0] = p3;
  120.      delw[0]   = p4;
  121.  
  122.                /* set up the rest of pointers */
  123.      for (i=1; i < (nhlayer + 1); i++)  {
  124.         wtptr[i] = wtptr[i-1] + nunit[i] * (nunit[i-1] + 1);
  125.         delw[i]  = delw[i-1] + nunit[i] * (nunit[i-1] + 1);
  126.      }
  127.      for (i=1; i < (nhlayer + 2); i++)  {
  128.         outptr[i] = outptr[i-1] + nunit[i-1] + 1;
  129.         errptr[i] = errptr[i-1] + nunit[i-1] + 1;
  130.      }
  131.  
  132.                /* set up threshold outputs */
  133.      for (i=0; i < nhlayer + 1; i++)  {
  134.         *(outptr[i] + nunit[i]) = 1.0;
  135.      }
  136. }
  137.  
  138.                /* initialize weights with random
  139.                   numbers between -0.5 and +0.5  */
  140. void initwt()
  141. {
  142.      int i, j;
  143.      
  144.      for (j=0; j < nhlayer + 1; j++)
  145.     for (i=0; i < (nunit[j] + 1) * nunit[j + 1]; i++)  {
  146.            *(wtptr[j] + i) = random() / pow(2.0,15.0) - 0.5;
  147.            *(delw[j] + i) = 0.0;
  148.         }
  149. }
  150.  
  151.                /* specify architecture of net and
  152.                   values of learning parameters  */
  153. void set_up()
  154. {
  155.      int i;
  156.  
  157.      eta = 0.9;
  158.      printf("\nMomentum rate eta (default = 0.9)?: ");
  159.      scanf("%f", &eta);
  160.  
  161.      alpha = 0.7;
  162.      printf("\nLearning rate alpha (default = 0.7)?: ");
  163.      scanf("%f", &alpha);
  164.  
  165.      maxe = 0.01;  maxep = 0.001;
  166.      printf("\nMax total error (default = 0.01)?: ");
  167.      scanf("%f", &maxe);
  168.      printf("\nMax individual error (default = 0.001)?: ");
  169.      scanf("%f", &maxep);
  170.  
  171.      cnt_num = 1000;
  172.      printf("\nMax number of iterations (default = 1000)?: ");
  173.      scanf("%d", &cnt_num);
  174.  
  175.      printf("\nNumber of hidden layers?: ");
  176.      scanf("%d", &nhlayer);
  177.  
  178.      for (i=0; i < nhlayer; i++)  {
  179.         printf("\n\tNumber of units for hidden layer %d?: ", i+1);
  180.         scanf("%d", &nunit[i+1]);
  181.      }
  182.  
  183.      printf("\nCreate error file?  (Enter 1 for yes, 0 for no) : ");
  184.      scanf("%d", &fplot10);
  185.  
  186.      printf("\nExecution starts ");
  187.      printf(" -- if many iterations specified, go out for coffee...\n");
  188.  
  189.      nunit[nhlayer+1] = noutattr;
  190.      nunit[0] = ninattr;
  191. }
  192.  
  193.                /* read file for net architecture and learning
  194.                   parameters.  File name has suffix _v.dat   */
  195. void dread(char *taskname)
  196. {
  197.      int i,j,c;
  198.      char var_file_name[20];
  199.  
  200.      strcpy(var_file_name, taskname);
  201.      strcat(var_file_name, "_v.dat");
  202.      if (( fp1 = fopen(var_file_name, "r")) == NULL)
  203.      {
  204.     perror("\n Cannot open data file ");
  205.         exit(0);
  206.      }
  207.  
  208.      fscanf(fp1, "%d%d%d%f%f%d%d", &ninput, &noutattr, &ninattr,
  209.                &eta, &alpha, &nhlayer, &cnt_num);
  210.      for (i=0; i < nhlayer + 2; i++)
  211.         fscanf(fp1, "%d", &nunit[i]);
  212.  
  213.      if ((c=fclose(fp1)) != 0)
  214.         printf("\nFile %s cannot be closed; error  %d ",
  215.                var_file_name, c);
  216. }
  217.  
  218.                /* read file containing weights and thresholds
  219.                   and thresholds.  File name has suffix _w.dat */
  220. void wtread(char *taskname)
  221. {
  222.      int  i,j,c;
  223.      char wt_file_name[20];
  224.  
  225.      strcpy(wt_file_name, taskname);
  226.      strcat(wt_file_name, "_w.dat");
  227.      if (( fp2 = fopen(wt_file_name, "r")) == NULL)
  228.      {
  229.     perror("\n Cannot open data file ");
  230.         exit(0);
  231.      }
  232.      
  233.      for (i=0; i < nhlayer + 1; i++)  {
  234.         for (j=0; j < (nunit[i] + 1) * nunit[i + 1]; j++)  {
  235.            fscanf(fp2, "%f", (wtptr[i]+j));
  236.         }
  237.      }
  238.  
  239.      if ((c = fclose(fp2)) != 0)
  240.         printf("\n File %sf cannot be closed; error %d ",
  241.                 wt_file_name, c);
  242.  
  243. }
  244.  
  245.                /* create file for net architecture and learning
  246.                   parameters.  File name has suffix _v.dat */
  247. void dwrite(char *taskname)
  248. {
  249.      int i,j,c;
  250.      char var_file_name[20];
  251.  
  252.      strcpy(var_file_name, taskname);
  253.      strcat(var_file_name, "_v.dat");
  254.      if ((fp1 = fopen(var_file_name, "w+")) == NULL)
  255.      {
  256.     perror(" Cannot open data file ");
  257.         exit(0);
  258.      }
  259.      fprintf( fp1, "%u %u %u %f %f %u %u\n", ninput, noutattr,
  260.           ninattr, eta, alpha, nhlayer, cnt_num);
  261.  
  262.      for (i=0; i < nhlayer + 2; i++)  {
  263.         fprintf(fp1, "%d ", nunit[i]);
  264.      }
  265.  
  266.      fprintf(fp1, "\n%d %f\n", cnt, err_curr);
  267.  
  268.      for (i=0; i < ninput; i++)
  269.      {
  270.         for (j=0; j < noutattr; j++)
  271.            fprintf(fp1, "%f      ", outpt[i][j]);
  272.         fprintf(fp1, "\n");
  273.      }
  274.  
  275.      if ((c=fclose(fp1)) != 0)
  276.         printf("\nFile %s cannot be closed; error %d ", 
  277.                var_file_name, c);
  278. }
  279.  
  280.                /* create file for saving weights and thresholds
  281.                   learned from training.  File name has suffix
  282.                   _w.dat */
  283. void wtwrite(char *taskname)
  284. {
  285.      int i,j,c,k;
  286.      char wt_file_name[20];
  287.  
  288.      strcpy(wt_file_name, taskname);
  289.      strcat(wt_file_name, "_w.dat");
  290.  
  291.      if ((fp2 = fopen(wt_file_name, "w+")) == NULL)
  292.      {
  293.     perror("\nCannot open data file ");
  294.         exit(0);
  295.      }
  296.      
  297.      k=0;
  298.      for (i=0; i < nhlayer + 1; i++)
  299.         for (j=0; j < (nunit[i] + 1) * nunit[i + 1]; j++)  {
  300.            if(k==8)  {
  301.               k=0;
  302.               fprintf(fp2, "\n");
  303.            }
  304.            fprintf(fp2, "%f ", *(wtptr[i] + j));
  305.            k++;
  306.         }
  307.         if ((c=fclose(fp2)) != 0)
  308.            printf("\nFile %s cannot be closed; error %d ",
  309.                     wt_file_name, c);
  310. }
  311.  
  312.                /* bottom_up calculation of net for input
  313.                   pattern i                              */
  314. void forward(int i)
  315. {
  316.      int m,n,p,offset;
  317.      float net;
  318.  
  319.                     /* input level output calculation */
  320.      for (m=0; m < ninattr; m++)
  321.         *(outptr[0]+m) = input[i][m];
  322.  
  323.                     /* hidden & output layer output calculation */
  324.      for (m=1; m < nhlayer + 2; m++)  {
  325.         for (n=0; n < nunit[m]; n++)  {
  326.            net = 0.0;
  327.            for (p=0; p < nunit[m-1] + 1; p++)  {
  328.           offset = (nunit[m-1] + 1) * n + p;
  329.               net += *(wtptr[m-1] + offset) *
  330.                          (*(outptr[m-1] + p));
  331.            }
  332.        *(outptr[m]+n) = 1 / (1 + exp(-net));
  333.         }
  334.      }
  335.      for (n=0; n < nunit[nhlayer + 1]; n++)
  336.         outpt[i][n] = *(outptr[nhlayer + 1] + n);
  337. }
  338.  
  339.                /* several conditions are checked to see
  340.                   whether learning should terminate   */
  341. int introspective(int nfrom, int nto)
  342. {
  343.      int i, flag;
  344.  
  345.                     /* reached max. iteration */
  346.      if (cnt >= cnt_num) return(FEXIT);
  347.  
  348.                     /* error for each pattern small enough? */
  349.      nsnew = 0;
  350.      flag = 1;
  351.      for (i = nfrom; (i < nto) && (flag == 1); i++)  {
  352.         if (ep[i] <= maxep) nsnew++;
  353.         else flag = 0;
  354.      }
  355.      if (flag == 1) return (SEXIT);
  356.  
  357.                     /* system total error small enough? */
  358.      if (err_curr <= maxe) return (SEXIT);
  359.      return(CONTNE);
  360. }
  361.  
  362.                /* threshold is treated as weight of link from
  363.                   a virtual node whose output value is unity */
  364. int rumelhart(int from_snum, int to_snum)
  365. {
  366.      int i,j,k,m,n,p,offset,index;
  367.      float out;
  368.      char *err_file = "criter.dat";
  369.  
  370.      nsold = 0;
  371.      cnt = 0;
  372.      result = CONTNE;
  373.      
  374.      if (fplot10)
  375.         if ((fp3 = fopen(err_file, "w")) == NULL)
  376.         {
  377.        perror( "\nCannot open error file ");
  378.            exit(0);
  379.         }
  380.         do {
  381.         err_curr = 0.0;
  382.                          /* for each pattern */
  383.         for (i=from_snum; i < to_snum; i++) {
  384.        forward(i);   /* bottom_up calculation */
  385.  
  386.                          /* top_down error propagation */
  387.                          /* output_level error */
  388.        for (m=0; m < nunit[nhlayer + 1]; m++)  {
  389.               out = *(outptr[nhlayer + 1] + m);
  390.               *(errptr[nhlayer + 1] + m) = (target[i][m] - out) *
  391.                               (1 - out) * out;
  392.            }
  393.  
  394.                          /* hidden & input layer errors */
  395.            for (m=nhlayer + 1; m >= 1; m--)  {
  396.               for (n=0; n < nunit[m-1]+1; n++)  {
  397.                  *(errptr[m-1] + n) = 0.0;
  398.                  for (p=0; p < nunit[m]; p++)  {
  399.                     offset = (nunit[m-1] + 1) * p + n;
  400.                     *(delw[m-1]+offset) = eta * (*(errptr[m]+p))
  401.                               * (*(outptr[m-1] + n))
  402.                               + alpha * (*(delw[m-1] + offset));
  403.                     *(errptr[m-1]+n) += *(errptr[m] + p)
  404.                               * (*(wtptr[m-1] + offset));
  405.                  }
  406.                  *(errptr[m-1] + n) = *(errptr[m-1] + n) *
  407.                               (1 - *(outptr[m-1] + n))
  408.                   * (*(outptr[m-1] + n));
  409.               }          
  410.           }   
  411.  
  412.                          /* weight changes */
  413.           for (m=1; m < nhlayer + 2; m++)  {
  414.              for (n=0; n < nunit[m]; n++)  {
  415.                 for (p=0; p < nunit[m-1] + 1; p++)  {
  416.                    offset = (nunit[m-1] + 1) * n + p;
  417.                    *(wtptr[m-1] + offset) += *(delw[m-1] + offset);
  418.                 }
  419.              }
  420.           }
  421.  
  422.           ep[i] = 0.0;
  423.           for (m=0; m < nunit[nhlayer + 1]; m++)  {
  424.              ep[i] += fabs((target[i][m] -
  425.                      *(outptr[nhlayer+1] + m)));
  426.           }
  427.           err_curr += ep[i] * ep[i];
  428.         }                /* normalized system error */
  429.         err_curr = 0.5 * err_curr / ninput;
  430.  
  431.                          /** save errors in file to draw the
  432.                              system error with plot10      **/
  433.         if (fplot10)
  434.            fprintf(fp3, "%1d, %2.9f\n", cnt, err_curr);
  435.         cnt++;
  436.  
  437.                     /* check condition for terminating learning */
  438.         result = introspective(from_snum, to_snum);
  439.      } while (result == CONTNE);  /* end of long do-while */
  440.  
  441.                     /* update output with changed weights */
  442.      for (i=from_snum; i < to_snum; i++) forward(i);
  443.  
  444.      for (i=0; i < nhlayer + 1; i++)  {
  445.         index = 0;
  446.         for (j=0; j < nunit[i+1]; j++)
  447.         {
  448.            printf("\n\nWeights between unit %d of layer %d",
  449.                           j, j+1);
  450.            printf(" and units of layer %d\n", i);
  451.            for (k=0; k < nunit[i]; k++)
  452.               printf(" %f", *(wtptr[i] + index++));
  453.            printf("\n  Threshold of unit %d of layer %d is %f",
  454.              j, i+1, *(wtptr[i] + index++));
  455.         }
  456.      }
  457.  
  458.      for (i=0; i < ninput; i++)
  459.         for (j=0; j < noutattr; j++)
  460.            printf("\n\n sample %d output %d = %f target %d = %f",
  461.                          i, j, outpt[i][j],j,target[i][j]);
  462.      printf("\n\nTotal number of iterations is %d", cnt);
  463.      printf("\nNormalized system error is %f\n\n\n", err_curr);
  464.      return(result);
  465. }
  466.  
  467.                          /* read in the input data file specified
  468.                             by user during interactive session */
  469. void user_session()
  470. {
  471.      int i,j,showdata;
  472.      char fnam[20], dtype[20];
  473.      FILE *fp;
  474.  
  475.      printf("\n Start of learning session");
  476.      
  477.                          /* for task with name task_name, input
  478.                             data file of the task is automatically
  479.                             set to be task_name.dat by program */
  480.      printf("\n Enter the task name : ");
  481.      scanf("%s", task_name);
  482.  
  483.      printf("\n How many features in input pattern?: ");
  484.      scanf("%d", &ninattr);
  485.      
  486.      printf("\n How many output units?: ");
  487.      scanf("%d", &noutattr);
  488.  
  489.      printf("\n Total number of input samples?: ");
  490.      scanf("%d", &ninput);
  491.  
  492.      strcpy(fnam, task_name);
  493.      strcat(fnam, ".dat");
  494.      
  495.      printf("\n Input file name is %s \n", fnam);
  496.      if ((fp = fopen(fnam, "r")) == NULL)
  497.      {
  498.         printf("\nFile %s does not exist", fnam);
  499.         exit(0);
  500.      }
  501.      
  502.      printf("\n Do you want to look at data just read? (Y/N): " );
  503.      scanf("%s", dtype);
  504.      showdata = ((dtype[0] == 'y') || (dtype[0] == 'Y'));
  505.      for (i=0; i < ninput; i++)  {
  506.         for (j=0; j < ninattr; j++)  {
  507.            fscanf(fp, "%f", &input[i][j]);
  508.            if (showdata) printf("%f  ", input[i][j]);
  509.         }
  510.         for (j=0; j < noutattr; j++)  {
  511.            fscanf(fp, "%f", &target[i][j]);
  512.            if (showdata) printf("%f\n", target[i][j]);
  513.         }
  514.      }
  515.      if ((i = fclose(fp)) != 0)
  516.      {
  517.         printf("\nFile %s cannot be closed; error %d ", fnam, i);
  518.         exit(0);
  519.      }
  520. }
  521.  
  522.                          /* main body of learning */
  523. void learning()
  524. {
  525.      int result;
  526.      
  527.      user_session();
  528.      set_up();
  529.      init();
  530.      do {
  531.         initwt();
  532.     result = rumelhart(0,ninput);
  533.      } while (result == RESTRT);
  534.  
  535.      if (result == FEXIT)
  536.      {
  537.     printf("\n Max number of iterations reached, but failed");
  538.     printf("\n to decrease system error sufficiently...\n");
  539.      }
  540.      dwrite(task_name);
  541.      wtwrite(task_name);
  542. }
  543.  
  544.                          /* main body of output generation */
  545. void output_generation()
  546. {
  547.      int i,m,nsample;
  548.      char ans[10];
  549.      char dfile[20];
  550.  
  551.                /* If task is already in the memory, data files
  552.                   for task do not need to be read in.  But, if it
  553.                   is a new task, data files should be read in to
  554.                   reconstruct the net.   */
  555.      printf("\nGeneration of outputs for a new pattern");
  556.      printf("\n\t Present task name is %s", task_name);
  557.      printf("\n\t Work on a different task? (Y or N): ");
  558.      scanf("%s", ans);
  559.      if ((ans[0]=='y') || (ans[0]=='Y'))
  560.      {
  561.         printf("\n\t Please enter the task name:  ");
  562.         scanf("%s", task_name);
  563.         dread(task_name);
  564.         init();
  565.         wtread(task_name);
  566.      }
  567.  
  568.                     /* input data for output generation
  569.                        are created                      */
  570.      printf("\nEnter file name for patterns to be processed: ");
  571.      scanf("%s", dfile);
  572.      if ((fp1=fopen(dfile, "r")) == NULL )
  573.      {
  574.     perror(" Cannot open dfile ");
  575.         exit(0);
  576.      }
  577.  
  578.      printf("\nEnter number of patterns for processing:  ");
  579.      scanf("%d", &nsample);
  580.  
  581.      for (i=0; i < nsample; i++)
  582.         for (m=0; m < ninattr; m++)
  583.            fscanf(fp1, "%f", &input[i][m]);
  584.  
  585.                     /* output generation calculation starts */
  586.      for (i=0; i < nsample; i++)
  587.      {
  588.         forward(i);
  589.         for (m=0; m < noutattr; m++)
  590.            printf("\n sample %d output %d = %f", 
  591.                     i, m, *(outptr[nhlayer + 1] + m));
  592.         printf("\n");
  593.      }
  594.      printf("\nOutputs have been generated ");
  595.  
  596.      if ((i=fclose(fp1)) != 0)
  597.         printf("\nFile %s cannot be closed; error %d", dfile, i);
  598. }
  599.  
  600. /************************  MAIN  *********************************/
  601. void main()
  602. {
  603.      char select[20], cont[10];
  604.  
  605.      strcpy(task_name, "*********");
  606.      do {
  607.         printf("\n**Select L(earning) or O(utput generation)**\n");
  608.         do {
  609.            scanf ("%s", select);
  610.            switch (select[0]) {
  611.               case 'o':
  612.               case 'O': output_generation();
  613.             break;
  614.               case 'l':
  615.               case 'L': learning();
  616.                         break;
  617.               default : printf("\n Please answer");
  618.                         printf(" learning or output generation ");
  619.                         break;
  620.            }
  621.         } while ((select[0] != 'o') && (select[0] != 'O')
  622.               && (select[0] != 'l') && (select[0] != 'L'));
  623.         printf("\nDo you want to continue?  ");
  624.         scanf( "%s", cont);
  625.      } while ((cont[0] == 'y') || (cont[0] == 'Y'));
  626.  
  627.      printf("\n\nIt is all finished. ");
  628.      printf("\nGood bye...\n\n\n  ");
  629. }
  630.                       
  631.